<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>关于深浅拷贝</title>
</head>

<body>
    <h1>学习资料参考冴羽</h1>
    <script>
        /** 因为js有基本数据类型和引用数据类型两种，
            基本数据类型存储在栈中，引用数据类型存在在堆中，因此对于引用数据类型也有了深浅拷贝的概念
        */

        // 对于两种数据类型的区别如下：
        /**
        对于基本数据类型：(Int,String,Number,Boolean,Undefined,Null)
            对一个变量进行初始化时，相当于在栈中开辟了一块内存存放这个变量，比如下面的a；
            当初始化另一个变量b时，让他等于a，相当于对a的值进行了复制
            之后在对a重新复制也不会影响b，b依然等于之前重新赋值之前的a的值

            这种情况就叫做深拷贝，基本数据类型都是深拷贝
        */
        console.warn('基本数据类型例子');
        let a = 54;
        let b = a;
        console.warn('初始化');
        console.log(`a=${a}`); //54
        console.log(`b=${b}`); //54
        a = 99;
        console.warn('重新对a赋值前前');
        console.log(`a=${a}`); //99
        console.log(`b=${b}`); //54
        /**
        对于引用数据类型：Object,Date,Arrary,RegExp
            创建一个对象num，定义a，b两个属性；对num.a进行复制54，对b赋值num.a;
            然后在对num.a重新赋值，后打印两个属性的值，发现b也跟着改变了;
            因为在对于引用数据类型，具体的数据存在对内存中，而变量只是存的这个值在堆中的地址；
            所以在num.b=num.a的操作中，只是把num.a的值的地址拷贝给了num.b而已

            这种情况就叫做浅拷贝
        */
        console.warn('引用数据类型例子1：对象');
        let num = {
            a: 0,
            b: 0
        };
        console.warn('初始化');
        console.log(`num.a=${num.a=54}`); //54
        console.log(`num.b=${num.b=num.a}`); //54
        console.warn('重新对a赋值后');
        console.log(`num.a=${num.a=99}`); //99
        console.log(`num.b=${num.b=num.a}`); //99
        console.warn('引用数据类型例子2：数组');
        let arr = [1, 2, 3];
        let brr = arr;
        console.warn('初始化');
        console.log(`arr=${arr}`);
        console.log(`brr=${brr}`);
        console.warn('重新赋值后');
        arr[0] = 100;
        console.log(`arr=${arr}`);
        console.log(`brr=${brr}`);
        // 对于数组一下也算是浅拷贝
        console.warn('对于存放的都是基本数据类型的数组进行拷贝，可以通过数组的concat和slice方法实现');
        console.warn('conact是连接两个数组并返回结果(一个新的数组)');
        console.warn('slice是截取数据的一部分并返回结果');
        let nums = [1, 2, 3];
        let Nums = nums.concat(); //num.slice
        console.warn('初始化');
        console.log(`nums=${nums}`); //123
        console.log(`Nums=${Nums}`); //123
        nums[0] = 100;
        console.warn('重新赋值后');
        console.log(`nums=${nums}`); //100，2，3
        console.log(`Nums=${Nums}`); //123
        console.warn('对于存放的是数组或者对对象的数组以上方法也会失效,所以这两种方法也算是浅拷贝');
        let objarr = [{
            name: 'wade'
        }];
        let objbrr = objarr;
        console.warn('初始化');
        console.log(`objarr=${objarr[0].name}`);
        console.log(`objbrr=${objbrr[0].name}`);
        console.warn('重新赋值后');
        objarr[0].name = 'kobe';
        console.log(`objarr=${objarr[0].name}`);
        console.log(`objbrr=${objbrr[0].name}`);
        /*
            对于数组实现深拷贝：
        */
        console.warn('通过json的api(对function无效)');
        let newobjarr = [{
            name: 'wade'
        }, {
            age: 1
        }];
        let newobjbrr = JSON.parse(JSON.stringify(newobjarr));
        console.warn('初始化');
        console.log(`newobjarr=${newobjarr[0].name}`);
        console.log(`newobjbrr=${newobjbrr[0].name}`);
        console.warn('重新赋值后');
        newobjarr[0].name = 'kobe';
        console.log(`newobjarr=${newobjarr[0].name}`);
        console.log(`newobjbrr=${newobjbrr[0].name}`);

        // 自己实现一个浅拷贝

        let demoArr = [{
            name: 'taotao'
        }, {
            name: 'guiyi'
        }];
        let simpleCopy = function (arg) {
            if (typeof arg != 'object') {
                return '只能传入对象';
            }
            // 通过instanceof判断传递进来的是数组还是对象
            let newarg = arg instanceof Array ? [] : {};
            for (let i in arg) {
                if (arg.hasOwnProperty(i)) {
                    newarg[i] = arg[i];
                };
            };
            return newarg;
        };
        let demo = simpleCopy(demoArr);
        console.warn('初始化');
        console.log(demoArr);
        console.log(demo);
        console.warn('重新赋值后');
        demoArr[0].name = 'haha';
        console.log(demoArr);
        console.log(demo);

        // 手动实现深拷贝  如果赋值过程中有对象的话就再次调用本函数利用递归实现
        let deepCopy = function (arg) {
            if (typeof arg != 'object') {
                return '只能传入对象';
            };
            // 通过instanceof判断传递进来的是数组还是对象
            let newarg = arg instanceof Array ? [] : {};
            for (let i in arg) {
                if (arg.hasOwnProperty(i)) {
                    newarg[i] = typeof arg[i] === 'object' ? deepCopy(arg[i]) : arg[i];
                };
            };
            return newarg;
        };
        let demoDeep = [{
            name: 'deep'
        }, {
            name: 'deep'
        }];
        let test = deepCopy(demoDeep);
        console.warn('初始化');
        console.log(demoDeep);
        console.log(test);
        console.warn('重新赋值后');
        demoDeep[0].name = 'test';
        console.log(demoDeep);
        console.log(test);

        let one = function () {
            console.log('a');
        };
        let two=function(){
            console.log('b');
        };
        let sx = [one,two];
        let gy=JSON.parse(JSON.stringify(sx));
        console.log(sx);
        console.log(gy);
    </script>
</body>

</html>